#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <future>
#include "Multigrid.h"
#include "Factory.h"

using namespace std;

typedef SingletonHolder<Factory<AbstractMultigrid, tuple<int, string, string, string> > > MultigridFactory;

void Run(int Dim, string Cycle, string Restriction, string Interpolation);

mutex m;

int main()
{
	try {
		Register();
		int Dim;
		string Cycle, Restriction, Interpolation;
		ifstream in("input.txt", ios::in);
		thread thread_array[100];
		int id = 0;
		while (in >> Dim >> Cycle >> Restriction >> Interpolation)
			thread_array[id++] = thread(Run, Dim, Cycle, Restriction, Interpolation);
		in.close();
		for (int i = 0; i < id; ++i)
			thread_array[i].join();
	} catch (exception &e) {
		cerr << e.what() << endl;
	}
	
	return 0;
}

void Run(int Dim, string Cycle, string Restriction, string Interpolation)
{
	Vector v, boundary;
	unique_lock<mutex> lock(m);
	shared_ptr<AbstractMultigrid> multigrid(MultigridFactory::Instance().CreateObject(make_tuple(Dim, Cycle, Restriction, Interpolation)));
	lock.unlock();

	for (int n = 128; n <= 1024; n *= 2) {
		ofstream output("../data/" + to_string(Dim) + "_" + to_string(n) + "_"
				+ Cycle + "_" + Restriction + "_" + Interpolation + ".txt");
		output << "#迭代次数 #误差 #误差收敛率 #残差 #残差下降速度" << endl;
		cout << "开始计算" << Dim << "维情形, " << "n = " << n << ", " << Cycle << ", " 
			 << Restriction << ", " << Interpolation << "..." << endl;
		if (Dim == 1) {
			v = Vector(n - 1);
			boundary = Vector(GetBoundary());
		} else {
			v = Vector((n - 1) * (n - 1));
			boundary = Vector(GetBoundary(n));
		}
		if (Cycle == "VCycle")
			multigrid->SetParams(n, v, boundary, 15, 1e-8); //n, init_guess, boundary, max_iter, epsilon
		else
			multigrid->SetParams(n, v, boundary, 1, 1e-8); //n, init_guess, boundary, max_iter, epsilon
		multigrid->Solve(output);
		output.close();
		cout << Dim << "维情形, " << "n = " << n << ", " << Cycle << ", " 
			 << Restriction << ", " << Interpolation << " 计算完毕" << endl;
	}
}

